/*
 * ScoreKeeper class is in charge of keeping track of:
 * strikes, balls, outs, innings and score, hits and errors during a game.
 */

#include "scorekeeper.h"

ScoreKeeper::ScoreKeeper(QVector<Player*> home, int hPitcher, QVector<Player*> away, int aPitcher)
{
    for(int i=0;i<9;i++){
        homeStats.push_back(new GameStatistic());
        awayStats.push_back(new GameStatistic());
    }
    homeScore=0;
    awayScore=0;
    homeHits=0;
    awayHits=0;
    homeErrors=0;
    awayErrors=0;
    strikes=0;
    balls=0;
    outs=0;
    inning=1;
    bottomHalfOfInning=false;
    REGULATION_INNINGS=9;
    MAX_NUMBER_OF_STRIKES=3;
    MAX_NUMBER_OF_BALLS=4;
    MAX_NUMBER_OF_OUTS=3;
    homeLineupPosition=0;
    awayLineupPosition=0;
    setHomeLineUp(home);
    setAwayLineup(away);
    atBat= awayLineup.at(awayLineupPosition);
    awayStats.at(awayLineupPosition)->incrementAtBats();
    first=0;
    second=0;
    third=0;
    homePitcher=hPitcher;
    homeLineup.at(homePitcher)->getPlayerStats().incrementGamesPitched();
    awayPitcher=aPitcher;
    awayLineup.at(awayPitcher)->getPlayerStats().incrementGamesPitched();
}

//copy constructor
ScoreKeeper::ScoreKeeper(ScoreKeeper *other){
    this->homeScore = other->getHomeScore();
    this->awayScore = other->getAwayScore();
    this->homeHits = other->getHomeHits();
    this->awayHits = other->getAwayHits();
    this->homeErrors = other->getHomeErrors();
    this->awayErrors = other->getAwayErrors();
    this->strikes = other->getStrikes();
    this->balls = other->getBalls();
    this->outs = other->getOuts();
    this->inning = other->getInning();
    this->bottomHalfOfInning = other->isBottomHalf();
    REGULATION_INNINGS = 9;
    MAX_NUMBER_OF_STRIKES=3;
    MAX_NUMBER_OF_BALLS=4;
    MAX_NUMBER_OF_OUTS=3;
    this->homeLineupPosition = other->getHomeLineupPosition();
    this->awayLineupPosition = other->getAwayLineupPosition();
    this->homeLineup = other->getHomeLineup();
    this->awayLineup = other->getAwayLineup();
    atBat = other->whosAtBat();
    first = other->whosOnFirst();
    second = other->whosOnSecond();
    third = other->whosOnThird();
    homePitcher = other->getHomePitcher();
    awayPitcher = other->getAwayPitcher();

    //copying stats at current state
    homeStats = *(new QVector<GameStatistic*>());
    for(int i=0; i<other->getHomeStats().size(); i++){
        homeStats.append(new GameStatistic(other->getHomeStats().at(i)));
    }
    awayStats = *(new QVector<GameStatistic*>());
    for(int i=0; i<other->getAwayStats().size(); i++){
        awayStats.append(new GameStatistic(other->getAwayStats().at(i)));
    }
}

ScoreKeeper::~ScoreKeeper(){
    delete atBat;
    delete first;
    delete second;
    delete third;
}

int ScoreKeeper::getHomeScore(){
    return homeScore;
}

int ScoreKeeper::getAwayScore(){
    return awayScore;
}

//adds runs to the batting team
void ScoreKeeper::addToScore(int runs){
    if(isBottomHalf()){
        homeScore+=runs;
    }
    else{
        awayScore+=runs;
    }
    if(isGameOver()){
        emit gameOver();
    }
}

int ScoreKeeper::getHomeHits(){
    return homeHits;
}

int ScoreKeeper::getAwayHits(){
    return awayHits;
}

//adds hits to the batting team;
void ScoreKeeper::incrementHits(){
    if(isBottomHalf()){
        homeHits++;
    }
    else{
        awayHits++;
    }
}

int ScoreKeeper::getHomeErrors(){
    return homeErrors;
}

int ScoreKeeper::getAwayErrors(){
    return awayErrors;
}

//adds errors to the pitching team
void ScoreKeeper::addToErrors(int errors){
    if(isBottomHalf()){
        awayErrors+=errors;
    }
    else{
        homeErrors+=errors;
    }
}

int ScoreKeeper::getStrikes(){
    return strikes;
}

int ScoreKeeper::getBalls(){
    return balls;
}

int ScoreKeeper::getOuts(){
    return outs;
}

int ScoreKeeper::getInning(){
    return inning;
}

bool ScoreKeeper::isBottomHalf(){
    return bottomHalfOfInning;
}


void ScoreKeeper::incrementStrikes(){
    if(strikes==2){
        if(bottomHalfOfInning){
            homeStats.at(homeLineupPosition)->incrementStrikeouts();
            awayStats.at(awayPitcher)->incrementStrikeoutsPitched();
        }
        else{
            awayStats.at(awayLineupPosition)->incrementStrikeouts();
            homeStats.at(homePitcher)->incrementStrikeoutsPitched();
        }

        incrementOuts();
        incrementLineupPosition();
    }
    else{
        strikes++;
    }
}

bool ScoreKeeper::incrementBalls(){
    if(balls==3){
        if(first!=0){
            if(second!=0){
                if(third!=0){
                    addToScore(1);
                }
            }
        }
        if(bottomHalfOfInning){
            homeStats.at(homeLineupPosition)->incrementWalks();
            awayStats.at(awayPitcher)->incrementWalksPitched();
        }
        else{
            awayStats.at(awayLineupPosition)->incrementWalks();
            homeStats.at(homePitcher)->incrementWalksPitched();
        }
        incrementLineupPosition();
        resetAtBat();
        return true;
    }
    else{
        balls++;
        return false;
    }
}

void ScoreKeeper::incrementOuts(){
    resetAtBat();
    if(bottomHalfOfInning){
        homeStats.at(homePitcher)->incrementInningsPitched();
    }
    else{
        awayStats.at(awayPitcher)->incrementInningsPitched();
    }
    if(outs==2){
        incrementLineupPosition();
        clearBases();
        if(bottomHalfOfInning){
            incrementInning();
        }
        else{
            resetInning();
        }
    }
    else{
        outs++;
    }

}

void ScoreKeeper::incrementInning(){
    inning++;
    resetInning();
    if(isGameOver()){
        emit gameOver();
    }
}

void ScoreKeeper::toggleBottomHalf(){
    bottomHalfOfInning= !bottomHalfOfInning;
    if(bottomHalfOfInning){
        atBat=homeLineup.at(homeLineupPosition);
        homeStats.at(homeLineupPosition)->incrementAtBats();
    }
    else{
        atBat=awayLineup.at(awayLineupPosition);
        awayStats.at(awayLineupPosition)->incrementAtBats();
    }
}

bool ScoreKeeper::isGameOver(){
    if(inning >= REGULATION_INNINGS){
        if(isBottomHalf() && homeScore > awayScore){
            return true;
        }
    }
    if(inning > REGULATION_INNINGS && homeScore != awayScore){
        return true;
    }
    return false;
}

void ScoreKeeper::resetAtBat(){
    strikes=0;
    balls=0;
}

void ScoreKeeper::resetInning(){
    outs=0;
    resetAtBat();
    toggleBottomHalf();
    if(isGameOver()){
        emit gameOver();
    }
}

void ScoreKeeper::foulBall(){
    if(strikes<2){
        incrementStrikes();
    }
}

void ScoreKeeper::setHomeLineUp(QVector<Player*> home){
    for(int i=0; i<9; i++){
        homeLineup.push_back(home.at(i));
        homeLineup.at(i)->getPlayerStats().incrementGamesPlayed();
    }
}

void ScoreKeeper::setAwayLineup(QVector<Player*> away){
    for(int i=0; i<9; i++){
        awayLineup.push_back(away.at(i));
        awayLineup.at(i)->getPlayerStats().incrementGamesPlayed();
    }
}

void ScoreKeeper::incrementLineupPosition(){
    if(isBottomHalf()){
        if(homeLineupPosition==8){
            homeLineupPosition=0;
        }
        else{
            homeLineupPosition++;
        }
        atBat=homeLineup.at(homeLineupPosition);
        homeStats.at(homeLineupPosition)->incrementAtBats();
        awayStats.at(awayPitcher)->incrementAtBatsFaced();

    }
    else{
        if(awayLineupPosition==8){
            awayLineupPosition=0;
        }
        else{
            awayLineupPosition++;
        }
        atBat=awayLineup.at(awayLineupPosition);
        awayStats.at(awayLineupPosition)->incrementAtBats();
        homeStats.at(homePitcher)->incrementAtBatsFaced();
    }
    resetAtBat();
}

Player* ScoreKeeper::whosAtBat(){
    if(isBottomHalf()){
        return homeLineup.at(homeLineupPosition);
    }
    else{
        return awayLineup.at(awayLineupPosition);
    }
}

Player* ScoreKeeper::whosOnFirst(){
    return first;
}

Player* ScoreKeeper::whosOnSecond(){
    return second;
}

Player* ScoreKeeper::whosOnThird(){
    return third;
}

//calculates the number of players who scored, handles stats accordingly
void ScoreKeeper::homerun(){
    incrementHits();
    int count=0;
    if(first != 0){
        count++;
        attributeRun(first);
    }
    if(second != 0){
        count++;
       attributeRun(second);
    }
    if(third != 0){
        count++;
        attributeRun(third);
    }


    if(bottomHalfOfInning){
        homeStats.at(homeLineupPosition)->increaseRunsBattedIn(count+1);
        homeStats.at(homeLineupPosition)->incrementRunsScored();
        homeStats.at(homeLineupPosition)->incrementHomeRuns();
        if(count == 3){
            homeStats.at(homeLineupPosition)->incrementGrandSlams();
        }
        awayStats.at(awayPitcher)->incrementHitsAllowed();
    }
    else{
        awayStats.at(awayLineupPosition)->increaseRunsBattedIn(count+1);
        awayStats.at(awayLineupPosition)->incrementRunsScored();
        awayStats.at(awayLineupPosition)->incrementHomeRuns();
        if(count == 3){
            awayStats.at(awayLineupPosition)->incrementGrandSlams();
        }
        homeStats.at(homePitcher)->incrementHitsAllowed();
    }
    addToScore(count+1);

    clearBases();
    incrementLineupPosition();
}

void ScoreKeeper::clearBases(){
    first=0;
    second=0;
    third=0;
}

void ScoreKeeper::single(){
    incrementHits();
    if(isBottomHalf()){
        homeStats.at(homeLineupPosition)->incrementSingles();
        awayStats.at(awayPitcher)->incrementHitsAllowed();
    }
    else{
        awayStats.at(awayLineupPosition)->incrementSingles();
        homeStats.at(homePitcher)->incrementHitsAllowed();
    }

    incrementLineupPosition();
}

void ScoreKeeper::hitDouble(){
    incrementHits();
    if(bottomHalfOfInning){
        homeStats.at(homeLineupPosition)->incrementDoubles();
        awayStats.at(awayPitcher)->incrementHitsAllowed();
    }
    else{
        awayStats.at(awayLineupPosition)->incrementDoubles();
        homeStats.at(homePitcher)->incrementHitsAllowed();
    }
    incrementLineupPosition();
}

void ScoreKeeper::triple(){
    incrementHits();
    if(bottomHalfOfInning){
        homeStats.at(homeLineupPosition)->incrementTriples();
        awayStats.at(awayPitcher)->incrementHitsAllowed();
    }
    else{
        awayStats.at(awayLineupPosition)->incrementTriples();
        homeStats.at(homePitcher)->incrementHitsAllowed();
    }
    incrementLineupPosition();
}

GameStatistic ScoreKeeper::getCurrentPlayerStats(){
    if(isBottomHalf()){
        return *homeStats.at(homeLineupPosition);
    }
    else{
        return *awayStats.at(awayLineupPosition);
    }
}

QVector<GameStatistic*> ScoreKeeper::getHomeStats(){
    return homeStats;
}

QVector<GameStatistic*> ScoreKeeper::getAwayStats(){
    return awayStats;
}

QVector<Player*> ScoreKeeper::getHomeLineup(){
    return homeLineup;
}

QVector<Player*> ScoreKeeper::getAwayLineup(){
    return awayLineup;
}

void ScoreKeeper::setFirst(Player* p){
    first=p;
}

void ScoreKeeper::setSecond(Player* p){
    second=p;
}

void ScoreKeeper::setThird(Player* p){
    third=p;
}

GameStatistic ScoreKeeper::getPlayerStats(Player* p){
    if(isBottomHalf()){
        for(int i=0; i<homeStats.size(); i++){

        }
    }
}

int ScoreKeeper::getHomeLineupPosition(){
    return homeLineupPosition;
}

int ScoreKeeper::getAwayLineupPosition(){
    return awayLineupPosition;
}

int ScoreKeeper::getHomePitcher(){
    return homePitcher;
}

int ScoreKeeper::getAwayPitcher(){
    return awayPitcher;
}

//returns the player lineup position. Assumes this player belongs to the team that is at bat
int ScoreKeeper::getPlayerLineupPosition(Player *p){
    if(bottomHalfOfInning){
        for(int i=0; i<homeLineup.size(); i++){
            if(p==homeLineup.at(i)){
                return i;
            }
        }
        return -1;
    }
    else{
        for(int i=0; i<awayLineup.size(); i++){
            if(p==awayLineup.at(i)){
                return i;
            }
        }
        return -1;
    }
}
 //atribute a run to the player on base
void ScoreKeeper::attributeRun(Player *p){
    int lineupPosition = getPlayerLineupPosition(p);
    if(lineupPosition >= 0 ){ //sanity check, should never be  < 0
        if(bottomHalfOfInning){
            homeStats.at(lineupPosition)->incrementRunsScored();
            awayStats.at(awayPitcher)->incrementEarnedRuns();

        }
        else{
            awayStats.at(lineupPosition)->incrementRunsScored();
            homeStats.at(homePitcher)->incrementEarnedRuns();
        }
    }
}

void ScoreKeeper::attributeRBI(){
    if(bottomHalfOfInning){
        if(homeLineupPosition == 0){
            homeStats.at(8)->incrementRunsBattedIn();
        }
        else{
            homeStats.at(homeLineupPosition-1)->incrementRunsBattedIn();
        }
    }
    else{
        if(awayLineupPosition == 0){
            awayStats.at(8)->incrementRunsBattedIn();
        }
        else{
            awayStats.at(awayLineupPosition-1)->incrementRunsBattedIn();
        }
    }
}

void ScoreKeeper::gameOver(){
    //stat saving
    for(int i=0; i<homeLineup.size(); i++){
        homeLineup.at(i)->getPlayerStats().addGameStatistic(homeStats.at(i));        
        awayLineup.at(i)->getPlayerStats().addGameStatistic(awayStats.at(i));
    }
    int id= QDate::currentDate().toString().toInt();
    for(int i=0; i<homeLineup.size(); i++){
        homeLineup.at(i)->getPlayerStats().pushLastGameToDB(homeLineup.at(i)->getId(),id) ;
        awayLineup.at(i)->getPlayerStats().pushLastGameToDB(awayLineup.at(i)->getId(), id);
    }
}
